/**
 * Copyright © 2013 Creativor Studio.
 * About license information, please see LICENSE.txt.
 */
package org.creativor.rayson.client.transport;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * An agent stands for an remote server.
 * 
 * @author creativor
 */
final class ServerAgent {

	private final ConnectionPool pool;
	private final InetSocketAddress address;
	private final Map<Long, HttpConnectionImpl> busyConnections;
	private final LinkedList<HttpConnectionImpl> idleConnections;

	ServerAgent(final ConnectionPool connectionPool,
			final InetSocketAddress address) {
		pool = connectionPool;
		this.address = address;
		this.busyConnections = new HashMap<>();
		this.idleConnections = new LinkedList<>();
	}

	/**
	 * Turn a connection back.
	 * 
	 * @param conn
	 */
	void back(final HttpConnectionImpl conn) {
		busyConnections.remove(conn.getId());
		idleConnections.add(conn);
	}

	/**
	 * @return
	 */
	private HttpConnectionImpl createConnection() {
		return new HttpConnectionImpl(pool.getNextConnId(), this);
	}

	@Override
	public boolean equals(final Object obj) {
		if (obj == null)
			return false;
		if (!(obj instanceof ServerAgent))
			return false;
		final ServerAgent that = (ServerAgent) obj;
		if (!this.address.equals(that.address))
			return false;
		return true;
	}

	/**
	 * @return the address
	 */
	public InetSocketAddress getAddress() {
		return address;
	}

	/**
	 * Get an connection out of this server agent.
	 * 
	 * @throws IOException
	 *             If any IO error.
	 */
	public HttpConnectionImpl getConnection() throws IOException {
		HttpConnectionImpl result = idleConnections.pollFirst();
		if (result == null) {
			result = createConnection();
			// Open new connection.
			result.open();
		}
		// Put result into busy map.
		busyConnections.put(result.getId(), result);
		return result;
	}

	/**
	 * Remove an http connection.
	 * 
	 * @param id
	 *            connection id.
	 */
	void remove(final long id) {
		this.busyConnections.remove(id);
	}
}